unit UFrameCondition;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, DB, UFrameConditionField, UVonConfig;

type
  TFrameCondition = class(TFrame)
    ScrollBox1: TScrollBox;
    EFirstField: TFrameConditionField;
  private
    { Private declarations }
    FList: TList;
    FTableDataset: TDataset;
    FOnLoadFields: TEventToLoadFields;
    procedure EventOfSelectedCondition(Sender: TObject);
    procedure EventOfDeletedCondition(Sender: TObject);
    procedure EventOfNewCondition(Sender: TObject);
    procedure EventOfLoadFields(TableIdx: Integer; Fields: TVonNameValueData);
    procedure SetOnLoadFields(const Value: TEventToLoadFields);
    procedure SetSQL(const Value: string);
    function GetSQL: string;
    procedure Clear;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetTables(ADataset: TDataset);
  published
    property OnLoadFields: TEventToLoadFields read FOnLoadFields write SetOnLoadFields;
    property SQL: string read GetSQL write SetSQL;
  end;

implementation

{$R *.dfm}

{ TFrameCondition }

procedure TFrameCondition.Clear;
var
  I: Integer;
begin
  for I := 0 to FList.Count - 1 do
    TFrameConditionField(FList[I]).Free;
  FList.Clear;
end;

constructor TFrameCondition.Create(AOwner: TComponent);
begin
  inherited;
  FList:= TList.Create;
  EFirstField.OnSelectedCondition:= EventOfSelectedCondition;
  EFirstField.OnDeletedCondition:= EventOfDeletedCondition;
  EFirstField.OnNewCondition:= EventOfNewCondition;
  EFirstField.OnLoadFields:= EventOfLoadFields;
end;

destructor TFrameCondition.Destroy;
begin
  Clear;
  FList.Free;
  inherited;
end;

procedure TFrameCondition.EventOfDeletedCondition(Sender: TObject);
var
  I, Idx: Integer;
begin
  Idx:= Flist.IndexOf(Sender);
  TFrameConditionField(FList[Idx]).Free;
  FList.Delete(Idx);
  for I := Idx to FList.Count - 1 do
    TFrameConditionField(FList[I]).Top:= I * 21 + 21;
end;

procedure TFrameCondition.EventOfLoadFields(TableIdx: Integer;
  Fields: TVonNameValueData);
begin
  if Assigned(FOnLoadFields) then
    FOnLoadFields(TableIdx, Fields);
end;

procedure TFrameCondition.EventOfNewCondition(Sender: TObject);
var
  Field: TFrameConditionField;
  I: Integer;
begin
  Field:= TFrameConditionField.Create(nil);
  FList.Insert(TFrameConditionField(Sender).Index, Field);
  Field.Index:= FList.Count;
  Field.Level:= TFrameConditionField(Sender).Level;
  if Assigned(FTableDataset) then
    Field.SetTables(FTableDataset);
  Field.OnSelectedCondition:= EventOfSelectedCondition;
  Field.OnDeletedCondition:= EventOfDeletedCondition;
  Field.OnNewCondition:= EventOfNewCondition;
  Field.OnLoadFields:= EventOfLoadFields;
  Field.Parent:= ScrollBox1;
  Field.Left:= 0;
  for I := 0 to FList.Count - 1 do
    TFrameConditionField(FList[I]).Top:= I * 21 + 21;
end;

procedure TFrameCondition.EventOfSelectedCondition(Sender: TObject);
begin

end;

procedure TFrameCondition.SetOnLoadFields(const Value: TEventToLoadFields);
begin
  FOnLoadFields := Value;
end;

procedure TFrameCondition.SetTables(ADataset: TDataset);
var
  I: Integer;
begin
  FTableDataset:= ADataset;
  EFirstField.SetTables(FTableDataset);
  for I := 0 to FList.Count - 1 do
    TFrameConditionField(FList[I]).SetTables(FTableDataset);
end;

(* Generator *)

function TFrameCondition.GetSQL: string;
var
  I, J, FLastLevel: Integer;
begin
  Result:= EFirstField.GetSQL;
  FLastLevel:= 0;
  for I := 0 to FList.Count - 1 do
    with TFrameConditionField(FList[I]) do begin
      case ECondition.ItemIndex of
      0: Result:= Result + ' AND ';
      1: Result:= Result + ' OR ';
      end;
      if Level > FLastLevel then begin
        for J := FLastLevel + 1 to Level do
          Result:= Result + '(';
        FLastLevel:= Level;
      end else if Level < FLastLevel then begin
        for J := Level + 1 to FLastLevel do
          Result:= Result + ')';
        FLastLevel:= Level;
      end;
      Result:= Result + GetSQL;
    end;
  for J := 0 to FLastLevel do
    Result:= Result + ')';
end;

procedure TFrameCondition.SetSQL(const Value: string);
var
  FLastLevel: Integer;
  P: PChar;
  procedure ToSQL(Field: TFrameConditionField; HasLinker: Boolean);
  begin
    while P^ in [' ', #13, #10] do Inc(P);
    while P^ = '(' do Inc(FLastLevel);
    if not Assigned(Field) then begin
      if FList.Count = 0 then
        EventOfNewCondition(EFirstField)
      else EventOfNewCondition(TFrameConditionField(FList[FList.Count - 1]));
      Field:= TFrameConditionField(FList[FList.Count - 1]);
    end;
    Field.Level:= FLastLevel;
    P:= Field.SetPSQL(P, HasLinker);
    FLastLevel:= Field.Level;
    while P^ = ')' do begin
      Dec(FLastLevel);
      Inc(P);
    end;
  end;
begin
  P:= PChar(Value);
  FLastLevel:= 0;
  Clear;
  if P^ = #0 then Exit;
  ToSQL(EFirstField, False);
  while P^ <> #0 do
    ToSQL(nil, true);
end;

end.
